package com.zte.claa.inficombo.csa.app.service.modbus.impl;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMasterService;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMsgReceiver;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMasterCommProps;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMasterConfig;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMsgWapper;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusRequestConfig;


/**
 * @author hxl
 *
 * 针对每个ModbusMasterConfig配置,实例化一个类对象
 */
public class ModbusMasterTcpServiceImpl implements ModbusMasterService{
	// 日志打印.
	private Logger logger = LoggerFactory.getLogger(ModbusMasterTcpServiceImpl.class);	
	//modbus device配置信息
	private ModbusMasterConfig modbusMasterConfig;
	//modbus主站请求配置列表
	private List<ModbusRequestConfig> modbusRequestConfigList;
	//modbus消息处理器
	private ModbusMsgReceiver modbusMsgReceiver;
	//modbus通讯参数
	private ModbusMasterCommProps modbusMasterCommProps;			
	//modbus4jtcp连接参数
	private IpParameters ipParameters;
	//modbus4j主站对象
	private ModbusMaster modbusMaster;
	//modubs4jfactory 工厂
	private ModbusFactory modbusFactory;
	//master设置超时时间,单位s
	private final static Integer TIMEOUT = 100;
	//master设置重连次数
	private final static Integer RETRIES = 2;
	//检测连接是否存活
	private final static boolean KEEPALIVE = true;
	//检测连接是否存活
	private final static boolean ENCAPSULATED = false;
	
	private int timeout;	
	private int retries;
	private boolean keepAlive;
	private boolean encapsulated;
	
	//寄存器读取间隔ms
	private final static int DEFAULT_INTERVAL = 3 * 1000;
	private int interval = DEFAULT_INTERVAL;

	private boolean isWorkon = true;
	
	private ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
	
	//构造
	public ModbusMasterTcpServiceImpl(ModbusMasterConfig modbusMasterConfig,
									ModbusMasterCommProps modbusMasterCommProps,
									List<ModbusRequestConfig> modbusRequestConfigList,
									ModbusMsgReceiver modbusMsgReceiver){
		
		this.modbusMasterConfig = modbusMasterConfig;
		this.modbusMasterCommProps = modbusMasterCommProps;
		this.modbusRequestConfigList = modbusRequestConfigList;
		this.modbusMsgReceiver = modbusMsgReceiver;	
		
		this.isWorkon = true;
	}

		
	/**
	 * 初始化
	 * @throws Exception
	 */
	public void init() throws Exception{
		if(modbusMasterConfig == null){
			return;
		}		
		//消息接受器初始化
		this.modbusMsgReceiver.init();			
		//预处理
		this.pretreatment();	
		//提交任务	
		executorService.submit(new Runnable(){
			@Override
			public void run() {
				taskRun();
			}
		});				
		logger.info("Launch modbus master read task succ ->" + modbusMasterConfig.getIp());
	}
		
	//预处理
	private void pretreatment() throws Exception{
		
		if(modbusMasterConfig == null){
			logger.error("Modbus Master config is illegal.");
			throw new IllegalArgumentException("Modbus Master config is illegal.");
		}
		timeout = (modbusMasterCommProps.getTimeout() == null) ? TIMEOUT : modbusMasterCommProps.getTimeout();
		retries = (modbusMasterCommProps.getRetries() == null) ? RETRIES : modbusMasterCommProps.getRetries();	
		keepAlive = (modbusMasterCommProps.getKeepAlive() == null) ? KEEPALIVE : modbusMasterCommProps.getKeepAlive();	
		encapsulated = (modbusMasterCommProps.getEncapsulated() == null) ? ENCAPSULATED : modbusMasterCommProps.getEncapsulated();
		
		//以下步骤不能颠倒
		//创建modbusFactory
		createModbusFactory();
		//创建ip参数
		createIpParameters();
		//创建master
		createModbusMaster();	
		//连接slave
		//connectToModbusSlave();
	}
	
	
	//任务
	private void taskRun(){
		try{
			interval = modbusMasterConfig.getCmdinterval();
		}catch (Exception e) {
			interval = DEFAULT_INTERVAL;
		}
		
		while(this.isWorkon){
			if(modbusRequestConfigList == null || modbusRequestConfigList.size() == 0){
				return;
			}		
			for(ModbusRequestConfig config : modbusRequestConfigList){
				try{
					dealwapperReadHoldingRegister(config);
				}catch (Throwable t) {
					logger.error("DealwapperReadHoldingRegister failed: " + t.getMessage());
					//出现异常尝试重连
					reconnectToModbusSlave();
					continue;
				}
				//这里休眠一下,防止连续请求太多导致modbusslave不响应
				try{
					Thread.sleep(10);
				}catch (Throwable ignor) {}	
			}
			try{
				Thread.sleep(interval);
			}catch (Throwable ignor) {}			
		}	
	}
		
		
	private void createModbusMaster() throws Exception{	
		createModbusMaster(keepAlive);
	}
		
	/**
	 * keepAlive 是否保活
	 * @param keepAlive
	 * @throws Exception
	 */
	private void createModbusMaster(boolean keepAlive) throws Exception{	
		
		modbusMaster = modbusFactory.createTcpMaster(ipParameters, keepAlive);
		modbusMaster.setTimeout(timeout);
		modbusMaster.setRetries(retries);
	}
		
	
	private void createModbusFactory()throws Exception{
		if(modbusFactory == null){
			modbusFactory = new ModbusFactory();		
		}
	}
		
	
	private void createIpParameters()throws Exception{
		createIpParameters(encapsulated);
	}
		
	/*
	 * encapsulated确定了协议帧是否是通过tcp封装的RTU结构,
	 * 采用modbus tcp/ip时，设为false, 采用modbus rtu over tcp/ip时，要设为true
	 */	
	private void createIpParameters(boolean encapsulated)throws Exception{
		if(ipParameters == null){
			ipParameters = new IpParameters();		
		}
		ipParameters.setHost(this.modbusMasterConfig.getIp());
		ipParameters.setPort(this.modbusMasterConfig.getPort());
        ipParameters.setEncapsulated(encapsulated);
	}
	
	@Override
	public ModbusMaster getModbusMaster() throws Exception {		
		return modbusMaster;
	}

	@Override
	public void connectToModbusSlave() throws Exception {			
		this.modbusMaster.init();
	}

	//重连modbus slave
	private void reconnectToModbusSlave() {
		try{
			this.modbusMaster.init();	
		}catch (Throwable t) {
			logger.error("Modbus master try reconnect failed,msg: " + t.getMessage());
		}			
	}
	
	
	@Override
	public boolean hasConnectToModbusSlave() throws Exception {	
		return modbusMaster.isConnected();
	}

	@Override
	public void closeConnectToModbusSlave() throws Exception {	
		modbusMaster.destroy();		
	}

	//读保持寄存器
	@Override
	public byte[] readHoldingRegister(int slaveId, int offset, int num) throws Exception {
        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, offset, num);
        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) modbusMaster.send(request);
        return response.getData();      
    }
		
	//处理保持寄存器的数据
	@Override
	public void dealwapperReadHoldingRegister(ModbusRequestConfig config) throws Exception {	
		byte[] data = readHoldingRegister(config.getSlaveid(), config.getOffset(), config.getRegisternum());
		ModbusMsgWapper msg = new ModbusMsgWapper(data, config);		
		modbusMsgReceiver.receive(msg);			
    }
	
	
	@Override
	public void destory() throws Exception{
		if(executorService != null){
			this.executorService.shutdown();
			this.isWorkon = false;			
			this.executorService = null;
		}
		if(modbusMsgReceiver != null){
			this.modbusMsgReceiver.destory();
		}
		if(ipParameters != null){
			ipParameters = null;
		}
		if(modbusFactory != null){
			modbusFactory = null;
		}
		if(modbusMaster != null){
			modbusMaster = null;
		}
	}
	
}
